﻿using System;
using System.Security.Cryptography;

namespace Job.Core.Security
{
    /// <summary>
    /// 基于 RSA 非对称算法实现私钥加密，公钥解密的封装(无法继承此类)。
    /// </summary>
    public sealed class Rsa
    {
        #region Properties

        private CspParameters param;
        private RSACryptoServiceProvider rsa;
        private BigInteger d;
        private BigInteger e;
        private BigInteger modulus;

        #endregion

        #region Constructor

        /// <summary>
        /// 初始化 Rsa 类的新实例。
        /// </summary>
        /// <param name="modulus">表示 RSA 算法的 Modulus 参数。</param>
        public Rsa(string modulus)
        {
            if (string.IsNullOrEmpty(modulus))
                throw new ArgumentNullException("modulus");

            param = new CspParameters();
            param.Flags = CspProviderFlags.UseMachineKeyStore;
            rsa = new RSACryptoServiceProvider(param);
            rsa = new RSACryptoServiceProvider();
            this.modulus = new BigInteger(Convert.FromBase64String(modulus));
        }

        #endregion

        #region Methods

        /// <summary>
        /// 使用 RSA 算法对文本进行加密（私钥加密）。
        /// </summary>
        /// <param name="data">要加密的明文。</param>
        /// <returns>加密后的密文。</returns>
        private string Encrypt(string data)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            int len = data.Length;
            int len1 = 0;
            int blockLen = 0;
            if ((len % 128) == 0)
                len1 = len / 128;
            else
                len1 = len / 128 + 1;
            string block = string.Empty;
            string temp = string.Empty;

            for (int i = 0; i < len1; i++)
            {
                if (len >= 128)
                    blockLen = 128;
                else
                    blockLen = len;
                block = data.Substring(i * 128, blockLen);
                byte[] oText = System.Text.Encoding.Default.GetBytes(block);
                BigInteger biText = new BigInteger(oText);
                BigInteger biEnText = biText.ModPow(d, modulus);
                string temp1 = biEnText.ToHexString();
                temp += temp1;
                len -= blockLen;
            }

            return temp;
        }

        /// <summary>
        /// 使用 RSA 算法数据进行解密（公钥解密）。
        /// </summary>
        /// <param name="data">要解密的密码数据。</param>
        /// <returns>解密后的明文。</returns>
        private string Decrypt(string data)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            int len = data.Length;
            int len1 = 0;
            int blockLen = 0;
            if ((len % 256) == 0)
                len1 = len / 256;
            else
                len1 = len / 256 + 1;

            string block = string.Empty;
            string temp = string.Empty;
            for (int i = 0; i < len1; i++)
            {
                if (len >= 256)
                    blockLen = 256;
                else
                    blockLen = len;
                block = data.Substring(i * 256, blockLen);
                BigInteger biText = new BigInteger(block, 16);
                BigInteger biEnText = biText.ModPow(e, modulus);
                string temp1 = System.Text.Encoding.Default.GetString(biEnText.GetBytes());
                temp += temp1;
                len -= blockLen;
            }

            return temp;
        }

        /// <summary>
        /// 使用RSA算法对文本进行加密（私钥加密）。
        /// </summary>
        /// <param name="data">要加密的明文文本。</param>
        /// <param name="d">表示 RSA 算法的 D 参数。</param>       
        /// <returns>加密后的密文。</returns>
        public string Encrypt(string data, string d)
        {           
            this.d = new BigInteger(Convert.FromBase64String(d));
            return Encrypt(data);
        }

        /// <summary>
        /// 使用RSA算法数据进行解密（公钥解密）。
        /// </summary>
        /// <param name="data">要解密的密码数据。</param>
        /// <param name="e">表示 RSA 算法的 E 参数。</param>       
        /// <returns>解密后的明文。</returns>
        public string Decrypt(string data, string e)
        {
            this.e = new BigInteger(Convert.FromBase64String(e));
            return Decrypt(data);
        }

        /// <summary>
        /// 释放所有资源。
        /// </summary>
        public void Clear()
        {
            rsa.Clear();
        }

        #endregion        
    }
}